#ifndef _THREAD_POOL_HPP_
#define _THREAD_POOL_HPP_

#include <queue>
#include <vector>
#include "Thread.hpp"
#include "Cond.hpp"
#include "log.hpp"

// using namespace Thread;

namespace Thread_Pool
{
    using func_t = std::function<void()>;

    static const int defaultnum = 5;

    static const int Sleep_Num = 0;

    template < class T >
    class ThreadPool
    {
    private:
        //ThreadPool(int num = 5,int sleep = 0)
        ThreadPool()
            :_n(5)
            ,_sleepnums(0)
            ,_isrunning(false)
        {
            // 执行线程。
            for(int i = 0;i < 5;++i)
            {
                // 缺乏this指针就调用不了。
                _threads.emplace_back(Thread::Thread([this](){this->HandlerTask();}));
            }
        }
        void WaitAllTcp()
        {
            if(_sleepnums)
                _cond.Broadcast();
        }
        void WaitSignalTcp()
        {
            if(_sleepnums)
                _cond.Signal();
        }
        void EnableRunning()
        {
            _isrunning = true;
        }

        // 只允许有一个对象或是指针。当然不允许赋值。
        ThreadPool(const ThreadPool<T> &) = delete;

        ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;

    public:
        // 线程池只要有一个就够了。
        // 所以我们好好管理。
        ThreadPool<T>* GetInc()
        {
            // 默认有几个线程一起调用线程池。
            if(inc == nullptr)
            {
                // 因为加锁是在里面加锁的，无法判断有几个。
                // 究竟哪一个线程加了锁。
                // 所以再判断一次。
                Lock_Manager lock(_mutex);

                //LogSpace::Logger::LogMessage(LogSpace::LogLevel::DEBUG,"Mylog1",64,LogSpace::log) << "申请指针";

                if(inc == nullptr)
                {
                    inc = new ThreadPool<T>();
                    LogSpace::Logger::LogMessage(LogSpace::LogLevel::DEBUG,"Mylog1",64,LogSpace::log) << "开始运行";
                    inc->Start();
                }
            }

            return inc;
        }

        ~ThreadPool()
        {
            // int n = _threads.size();
            // for(int i = 0;i < n;++i)
            // {
            //     _threads.pop_back();
            // }

            // n = _taskq.size();
            // for(int i = 0;i < n;++i)
            // {
            //     _taskq.pop();
            // }

            std::cout << "析构线程池 ！ " << std::endl;

            if(inc)
            {
                delete inc;
                inc = nullptr;
            }
        }

        void Start()
        {
            if(_isrunning)
            {
                return ;
            }

            EnableRunning();

            for(auto& e : _threads)
            {
                e.Start();
            }
        }
        void Stop()
        {
            if(_isrunning == false)
            {
                return ;
            }

            _isrunning = false;

            WaitAllTcp();
        }
        void Join()
        {
            for(auto& thread : _threads)
            {
                thread.Join();
            }
        }
        void Enqueue(const T& task)
        {
            if(_isrunning == false)
            {
                return ;
            }
            _taskq.push(task);
        }
        
        // 执行线程池中对应的函数。
        void HandlerTask()
        {
            char name[50];
            
            // 获取当前线程的名字。
            //pthread_getname_np(pthread_self(),name,sizeof(name));

            while(true)
            {
                T _t;

                // 访问临界资源
                {
                    Lock_Manager manager(_mutex);

                    // 等待进程队列插入新的任务 && 这个线程池是否在运行
                    while(_taskq.empty() && _isrunning)
                    {
                        ++_sleepnums;
                        _cond.Wait(_mutex);
                        --_sleepnums;
                    }

                    if(_isrunning == false)
                    {
                        LogSpace::Logger::LogMessage(LogSpace::LogLevel::DEBUG,"Mylog1",64,LogSpace::log) << "线程已退出";
                        // 退出时应当唤醒所有线程，怕线程处于休眠状态没被处理。
                        WaitAllTcp();
                        break;
                    }

                    _t = _taskq.front();
                    _taskq.pop();
                }

                // 都取出来了就没必要加锁了。
                _t();
            }
        }
    private:
        std::vector<Thread::Thread> _threads;
        std::queue<T> _taskq;
        Condition::Cond _cond;
        Mutex _mutex;
        int _n;

        bool _isrunning;

        int _sleepnums;

        // 示例
        static ThreadPool<T>* inc;
        static Mutex _lock;
    };

    // 初始化static对象。
    template < class T >
    ThreadPool<T>* ThreadPool<T>::inc = nullptr;

    template < class T >
    Mutex ThreadPool<T>::_lock;
}

#endif